package com.bluedon.ism.commons.service.impl;

import com.bluedon.ism.commons.dao.AccountDAO;
import com.bluedon.ism.commons.dao.OrganizationDAO;
import com.bluedon.ism.commons.entity.Account;
import com.bluedon.ism.commons.entity.District;
import com.bluedon.ism.commons.entity.Organization;
import com.bluedon.ism.commons.service.AccountService;
import com.bluedon.ism.commons.service.ConfigService;
import com.bluedon.ism.commons.shiro.UsernamePasswordRealmToken;
import com.bluedon.ism.commons.util.Constants;
import com.bluedon.ism.commons.util.Pager;
import com.bluedon.ism.commons.util.StringUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;

@Service(value="accountService")
public class AccountServiceImpl extends AuthorizingRealm implements AccountService {
	
    private static Log logger = LogFactory.getLog(AccountServiceImpl.class);
    
	@Resource(name="accountDAO")
	private AccountDAO accountDAO;
	public void setAccountDAO(AccountDAO accountDAO) {
		this.accountDAO = accountDAO;
	}
	
    @Resource(name="organizationDAO")
    private OrganizationDAO orgDao;
    public void setOrgDao(OrganizationDAO orgDao) {
        this.orgDao = orgDao;
    }
    
    @Resource
	private ConfigService configService;
	public void setConfigService(ConfigService configService) {
		this.configService = configService;
	}

	/* shiro extend override */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(
			PrincipalCollection principals) {
		//null usernames are invalid
        if (principals == null) {
            throw new AuthorizationException("PrincipalCollection method argument cannot be null.");
        }
        
        Set<String> realmNames = principals.getRealmNames();
        if (!realmNames.contains(Constants.ACCOUNT_REALM)) {
            return null;
        }
        
        String username = (String) getAvailablePrincipal(principals);
        Set<String> roleNames = getRoleNames(username);
        if (roleNames.isEmpty()) {
            return null;
        }
        
        Set<String> permissions = getPermissionsByRoleNames(roleNames);
        //get roleNames & permissions
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(roleNames);
        info.setStringPermissions(permissions);
        return info;
	}

	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(
			AuthenticationToken token) throws AuthenticationException {
		UsernamePasswordRealmToken upToken = (UsernamePasswordRealmToken) token;
		String username = upToken.getUsername();
		String password = new String(upToken.getPassword());
		
		Account account = getAccountByName(username);
		if(account == null)
			throw new UnknownAccountException();
		if(!account.getPassword().equals(password))
			throw new IncorrectCredentialsException();
		if(account.getDisabled() || account.getOrganization().getDisabled())
			throw new LockedAccountException();
		//清理缓存
//		clearCachedAuthorizationInfo(new SimplePrincipalCollection(username,Constants.ACCOUNT_REALM));
		return new SimpleAuthenticationInfo(username, password, Constants.ACCOUNT_REALM);
	}
	
	@Override
	public boolean supports(AuthenticationToken token) {
	    UsernamePasswordRealmToken upToken = (UsernamePasswordRealmToken) token;
	    return upToken != null && upToken.getRealm() != null && upToken.getRealm().equals(Constants.ACCOUNT_REALM);
	}
	
	@Override
	public void addAccount(Account account) {
		this.accountDAO.addAccount(account);
		accountDAO.flush();
	}

	@Override
	public void updateAccount(Account account) {
		this.accountDAO.updateAccount(account);
	}

	@Override
	public Account getAccountById(Long id) {
		return this.accountDAO.getAccountById(id);
	}

	@Override
	public Pager<Account> getPcAccountPage(int pageNo, int pageSize, String oid, String userName) {
		return this.accountDAO.getAccountPageByType(Constants.PC, pageNo, pageSize, oid, userName);
	}

	@Override
	public void deleteAccount(long aid) {
		this.accountDAO.deleteAccount(aid);
	}

	@Override
	public Account getAccountByName(String username) {
		return this.accountDAO.getAccountByName(username);
	}

	@Override
	public Account getAccountByEmail(String email) {
		return this.accountDAO.getAccountByEmail(email);
	}

    @Override
    public List<Organization> getOrgByDid(String did) {
        return this.orgDao.getOrgByDid(did);
    }


    @Override
    public void deleteManyAccount(String aidArray) {
        aidArray = StringUtil.getSQLInValues(aidArray);
        accountDAO.deleteManyAccount(aidArray);        
    }


    @Override
    public List<District> getFuzzyDistrictByDid(String did) {
        return orgDao.getFuzzyDistrictByDid(did);
    }


    @Override
    public List<Organization> getFuzzyOrgByOid(String oid,String area) {
    	if("nocenter".equals(area)){
    		return orgDao.getFuzzyOrgByOid2(oid);
    	}else {
    		return orgDao.getFuzzyOrgByOid(oid);
		}
    }

    @Override
    public List<Map<String, Object>> getOrgTreeByOid(String oid){
        List<Map<String, Object>> treeList = new ArrayList<Map<String,Object>>();
        List<Organization> list = orgDao.getFuzzyOrgByOid(oid);
        for (Organization o : list) {
            Map<String, Object> map = new HashMap<String, Object>();
            map.put("id", o.getOid());
//            map.put("name", o.getName() + "-" + o.getOid());
            map.put("name", o.getName());
            map.put("value", o.getOid());
            map.put("pId", o.getParentId());
            map.put("isParent", o.getParentId() != null ? false : true);
            treeList.add(map);
        }
        return treeList;
    }
    
    public Set<String> getRoleNames(String username) {
        return accountDAO.getRoleNames(username);
    }

    public Set<String> getPermissionsByRoleNames(Set<String> roleNames) {
        return accountDAO.getPermissionsByRoleNames(roleNames);
    }


    @Override
    public List<Map<String, Object>> getAccountListByName(String name) {
        List<Map<String, Object>> nameList = new ArrayList<Map<String,Object>>();
        if (StringUtil.isBlank(name))
            return nameList;
        if (logger.isDebugEnabled()) {
            logger.debug("======== getAccountListByName:  " + name +  "============");
        }   
        
        List<Account> list = accountDAO.getAccountListByName(name);
        for (Account account : list) {
            Map<String, Object> map = new HashMap<String, Object>();
            map.put("label", account.getRealname() );
            map.put("username", account.getUsername() );
            map.put("value", account.getAid());
            nameList.add(map);
        }
        return nameList;
    }
    
    @Override
    public Collection<String> getPermission(){
    	AuthorizationInfo info=getAuthorizationInfo(SecurityUtils.getSubject().getPrincipals());
    	return info.getStringPermissions();
    }
    
    @Override
    public void clearCachedAuthorizationInfoOnSessionExpiration(PrincipalCollection principal) {
        doClearCache(principal);
    }
    
    @Override
    public Pager<Account> getAidListConfig(Map<String, Object>map,int pageNo,int pageSize){
    	return accountDAO.getAidListConfig(map, pageNo, pageSize);
    }


    @Override
    public Pager<Account> searchAccount(String oid, String name, int pageNo, int pageSize) {
        return accountDAO.searchAccount(oid, name, pageNo, pageSize);
    }
    
    /**
	 * 查询所有用户
	 */
    @Override
	public List<Account> getAll(){
    	return accountDAO.findAll();
	}
    
    public Pager<Account> getSameOrgAccount(String keyword, Long oldAid, Long aid, int pageNo, int pageSize){
    	return accountDAO.getSameOrgAccount(keyword, oldAid, aid, pageNo, pageSize);
    }
}
